import random

from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from web import models
from django.conf import settings
from utils.tencent.sms import send_sms_single
from django_redis import get_redis_connection
from utils import encrypt
from web.forms.bootstrap import BootStrapForm


class RegisterModelForm(BootStrapForm, forms.ModelForm):
    password = forms.CharField(
        label='密码',
        min_length=8,
        max_length=18,
        error_messages={
            'min_length': "密码长度不能小于8位",
            'max_length': "密码长度不能超过18位"
        },
        widget=forms.PasswordInput
    )
    confirm_password = forms.CharField(label='确认密码', widget=forms.PasswordInput)
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
    code = forms.CharField(label='验证码')

    class Meta:
        model = models.UserInfo
        # 使用__all__ 页面上的表单顺序就是默认安装Model中字段的顺序，再按照自定义forms中的字段顺序
        # fields = "__all__"
        fields = ['username', 'email', 'password', 'confirm_password', 'mobile_phone', 'code']

    # def __init__(self, *args, **kwargs):
    #     super().__init__(*args, **kwargs)
    #     for name, field in self.fields.items():
    #         field.widget.attrs['class'] = 'form-control'
    #         field.widget.attrs['placeholder'] = '请输入%s' % (field.label,)

    def clean_username(self):
        username = self.cleaned_data['username']
        exist = models.UserInfo.objects.filter(username=username).exists()
        if exist:
            self.add_error('username', '用户名已存在')
        return username

    def clean_email(self):
        email = self.cleaned_data['email']
        exist = models.UserInfo.objects.filter(email=email).exists()
        if exist:
            self.add_error('email', '邮箱已存在')
        return email

    def clean_password(self):
        password = self.cleaned_data['password']
        print(password)
        encrypt_pwd = encrypt.md5(password)
        print(encrypt_pwd)
        return encrypt_pwd

    def clean_confirm_password(self):
        password = self.cleaned_data['password']  # field中必须顺序在confirm_password之前
        confirm_password = self.cleaned_data['confirm_password']
        encrypt_confirm_pwd = encrypt.md5(confirm_password)
        if encrypt_confirm_pwd != password:
            self.add_error('confirm_password', '两次密码不一致')
        return encrypt_confirm_pwd

    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data['mobile_phone']
        exist = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exist:
            self.add_error('mobile_phone', '手机号已存在')
        return mobile_phone

    def clean_code(self):
        mobile_phone = self.cleaned_data['mobile_phone']
        code = self.cleaned_data['code']
        # conn = get_redis_connection()
        # redis_code = conn.get(mobile_phone)
        # if not redis_code:
        #     self.add_error('code', '验证码失效或者未发送，请重新发送')
        # else:
        #     redis_code_str = redis_code.decode('utf-8')
        #     if redis_code_str != code.strip():
        #         self.add_error('code', '验证码错误，请重新输入')
        return code


# 继承Form而不是ModelForm 因为这里我们只用来做数据校验，和数据库无关
class SendSmsForm(forms.Form):
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    # 定义钩子函数
    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data['mobile_phone']
        tpl = self.request.GET.get('tpl')
        template_id = settings.SMS_TEMPLATE_IDS.get(tpl)
        if not template_id:
            raise ValidationError('短信模板错误')

        if tpl == 'login':
            # 校验数据库中手机号是否不存在
            exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
            if not exists:
                # 不存在，抛出异常
                raise ValidationError('手机号不存在')
        else:
            # 校验数据库中手机号是否已经存在
            exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
            if exists:
                # 已经存在，抛出异常
                raise ValidationError('手机号已存在')
        # 发短信
        # 短信已经测试通过 这里为了测试后续方便 短信先不发 短信验证码固定为9999
        # code = random.randrange(1000, 9999)
        # result = send_sms_single(mobile_phone, template_id, [code, ])
        # if result['result'] != 0:
        #     raise ValidationError("短信发送失败，{}".format(result['errmsg']))
        # else:
        #     # 发送成功 写入redis (使用django-redis)
        #     conn = get_redis_connection()
        #     conn.set(mobile_phone, code, ex=60)
        # return mobile_phone
        code = 9999
        # 发送成功 写入redis (使用django-redis)
        conn = get_redis_connection()
        conn.set(mobile_phone, code, ex=60)
        return mobile_phone


# 短信登录Form
class LoginSmsForm(BootStrapForm, forms.Form):
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
    code = forms.CharField(label='验证码')

    # 使用了bootstrap表单后 基本上都要使用这个样式 所以下面的代码可以定义到一个类中，如本文件中定义的BootStrap，然后通过继承达到同样的效果
    # def __init__(self, *args, **kwargs):
    #     super().__init__(*args, **kwargs)
    #     for name, field in self.fields.items():
    #         field.widget.attrs['class'] = 'form-control'
    #         field.widget.attrs['placeholder'] = '请输入%s' % (field.label,)
    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data['mobile_phone']
        # exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        user_obj = models.UserInfo.objects.filter(mobile_phone=mobile_phone).first()
        if not user_obj:
            raise ValidationError('手机号不存在')
        return user_obj  # 这里直接把用户对象返回到 mobile_phone这个属性字段里 为了登录成功直接方便的设置到session里面

    def clean_code(self):
        code = self.cleaned_data['code']
        user_obj = self.cleaned_data.get('mobile_phone')
        if not user_obj:
            return code
        conn = get_redis_connection()
        redis_code = conn.get(user_obj.mobile_phone)
        if not redis_code:
            raise ValidationError('验证码失效或未发送，请重新发送')

        redis_code_str = redis_code.decode('utf-8')
        if code.strip() != redis_code_str:
            raise ValidationError('验证码错误，请重新输入')
        return code
